<template>
  <MyContainer>
    <div class="msg-box">
      <div class="msg-box-top">
        <div class="title">默认聊天室</div>
      </div>
      <div class="msg-box-content">
        <div class="msg-box-content-left">
          <div class="msg-box-content-msg-box" ref="msgBox">
            <!-- 使用teleport进行填充内容 -->
          </div>

          <div class="msg-box-content-input-box">
            <div class="bq-box">
              <span
                class="iconfont icon-biaoqing icon"
                @click="openBox('bq')"
              ></span>
              <span class="iconfont icon-tupian icon"></span>
              <span class="iconfont icon-jietu icon"></span>
              <span class="iconfont icon-liaotianjilu icon"></span>
            </div>
            <textarea
              class="send-msg-box"
              @focus="closeBox"
              v-model="sendEntity.text"
              @keydown.enter="sendMsg"
            />

            <div class="send-btn-box">
              <button @click="sendMsg">发送</button>
            </div>
          </div>
        </div>

        <div class="msg-box-content-right">
          <div class="top">
            <div style="display: inline-block; text-align: left">
              <p>
                <span>在线人数:</span><b>{{ online }}</b
                >人
              </p>
              <p>
                <span>登陆人:</span><b>{{ userName }}</b>
              </p>

              <p>
                <button @click="logout">退出登录</button>
              </p>
            </div>
          </div>
          <div class="bottom">
            <div class="title">在线人员列表</div>
            <div class="onlin-list"></div>
          </div>
        </div>
      </div>
    </div>
  </MyContainer>

  <teleport to=".onlin-list">
    <ul>
      <li v-for="(item, index) in onlineUsers" :key="index">
        {{ item }}
        <span
          style="
            font-size: 8px;
            color: green;
            padding-left: 2px;
            font-weight: 900;
          "
          v-if="store.getters.getUserInfo.name === item"
        >
          (当前用户)
        </span>
      </li>
    </ul>
  </teleport>

  <teleport to=".msg-box-content-msg-box">
    <div class="bq-container" v-show="bqBox.open">
      <span
        v-for="item in bqBox.items"
        :key="item.name"
        class="bq-item"
        @click="bqClick(item.name)"
      >
        <img :src="item.img" :alt="item.name + '.gif'" />
      </span>
    </div>
  </teleport>

  <teleport to=".msg-box-content-msg-box">
    <template v-for="(msgItem, index) in msgBox" :key="index">
      <div class="msg-item" v-if="msgItem.cmdType === 0">
        <div class="sys-msg">
          <p class="times">
            <span>{{ msgItem.sendTime }}</span>
          </p>
          <span class="sys-msg-box" v-html="msgItem.msg">
          </span>
        </div>
      </div>

      <div class="msg-item" v-if="msgItem.cmdType === 2">
        <div class="you-msg">
          <p>
            <span class="name">{{ msgItem.sender }}</span>
            <span class="times">{{ msgItem.sendTime }}</span>
          </p>
          <span class="you-msg-box"  v-html="msgItem.msg"></span>
        </div>
      </div>

      <div class="msg-item" v-if="msgItem.cmdType === 1">
        <div class="me-msg">
          <p>
            <span class="name">{{ msgItem.sender }}</span>
            <span class="times">{{ msgItem.sendTime }}</span>
          </p>
          <span class="me-msg-box" v-html="msgItem.msg"></span>
        </div>
      </div>
    </template>
  </teleport>
</template>

<script lang='ts'>
import { defineComponent } from "vue";
import { useStore } from "vuex";

import MyContainer from "@/components/MyContainer.vue";

import { AutheUtils } from "@/utils";
import { SocketHelper, EventType, HandlerType, MessageHandler } from "@/types";
import { useUserAPI } from "@/server";
const userAPI = useUserAPI();

export default defineComponent({
  name: "index",
  components: {
    MyContainer,
  },
  data() {
    return {
      bqBox: {
        open: false,
        items: [],
      },
      /* 如何显示消息 1普通消息 2图片消息 3语音消息
         命令类型 0系统消息 1你发送的消息 2非自己的消息
      */
      msgBox: [] as any[],
      online: 0,
      onlineUsers: [],
      sh: null as any,
      sendEntity: {
        text: "",
      },
      heartInterval:null as any|number
    };
  },
  setup(props, context) {
    const store = useStore();

    return {
      store,
    };
  },
  async created() {
    const store = useStore();

    this.initBqItems();

    let userInfo: any = await this.getUserInfo();

    if (!userInfo || !userInfo.name) {
      var name: string = prompt("请输入你的名称") as string;
      await this.setUserName(name);
      userInfo = await this.getUserInfo();
    }

    store.commit("setUserInfo", userInfo);

    this.initSocket();
  },
  computed: {
    userName() {
      const store = useStore();
      return store.getters.getUserInfo?.name;
    },
  },
  destroyed() {
    this.clearHeartInterval()
  },
  methods: {
    sendMsg() {
      if (!this.sendEntity.text || this.sendEntity.text.length === 0) {
        alert("发送内容不能为空");
        return;
      }
      let msg: any = {
        cmdType: 2,
        msg: this.sendEntity.text,
      };
      (this.sh as SocketHelper).sendMsg(JSON.stringify(msg));
      this.sendEntity.text = "";
    },
    bqClick(name: number) {
      console.log(name);
      this.sendEntity.text = this.sendEntity.text + this.formatImgFlag(name);
    },
    logout() {
      let flag = confirm("是否退出聊天室?");
      if (!flag) {
        return;
      }
      const token = AutheUtils.removeToken();
      this.sh.close();

      const router = this.$router;
      router.push({
        name: "login",
      });
    },
    setUserName(name: string) {
      return new Promise((resolve, reject) => {
        userAPI
          .setUserName(name)
          .then((res) => {
            const { data } = res;
            if (data.code == 200) {
              resolve(data.data);
            } else {
              reject(data.msg);
            }
          })
          .catch(reject);
      });
    },
    getUserInfo() {
      return new Promise((resolve, reject) => {
        userAPI
          .getUserInfo()
          .then((res) => {
            const { data } = res;
            if (data.code == 200) {
              resolve(data.data);
            } else {
              reject(data.msg);
            }
          })
          .catch(reject);
      });
    },
    initSocket() {
      const handler = new MessageHandler();
      handler.registeEvent(HandlerType.FLUSH_MESSAGE, this.renderMsg);
      handler.registeEvent(HandlerType.FLUSH_ONLINE, this.flushOnline);
      handler.registeEvent(HandlerType.FLUSH_ONLINE_LIST, this.flushOnlineList);

      const $t = this;
      const userInfo = $t.store.getters.getUserInfo;
      const wsh = (this.sh = new SocketHelper("ws://localhost:10086/ws"));


      wsh.onEvent(EventType.OPEN, function (e) {
        console.log("open")
        const { target: ws } = e;
        var cmdData = {
          cmdType: 1,
          name: userInfo.name,
        };
        ws.send(JSON.stringify(cmdData));

        $t.initHeartPongMsgPack(ws);
      });

       wsh.onEvent(EventType.CLOSE, function (messageEvent) {
         console.log("close")
          $t.clearHeartInterval();
       });

      wsh.onEvent(EventType.MESSAGE, function (messageEvent) {
         console.log("message")

        const { data, target: ws } = messageEvent;
        let msgObj = JSON.parse(data);
        console.log(msgObj);
        handler.handle(msgObj);
      });
    },
    clearHeartInterval(){
      if(this.heartInterval){
        clearInterval(this.heartInterval);
        this.heartInterval = null;
      }
    },
    initHeartPongMsgPack(ws:any){
        if(this.heartInterval){
            clearInterval(this.heartInterval as any)
        }
      this.heartInterval = setInterval(()=>{
        var cmdData = {
          cmdType: 101,
        };
        try {
          ws.send(JSON.stringify(cmdData))
        } catch (error) {
           clearInterval(this.heartInterval);
           console.log(`心跳发送失败，连接断开，任务已关闭`)
        }
      },7000);

    },
    formatImgFlag(flag: number) {
      return `[&bq#${flag}]`;
    },
    checkAndScrollDown() {
      this.$nextTick(() => {
        (this.$refs["msgBox"] as Element).scrollTo(0,(this.$refs["msgBox"] as Element).scrollHeight);
      });
    },
    // 渲染消息到聊天框
    renderMsg(msgObj: any) {
      this.formatMessage(msgObj);
      this.msgBox.push(msgObj);
      this.checkAndScrollDown();
    },
    // 刷新在线人数
    flushOnline(msgObj: any) {
      this.online = msgObj.online;
    },
    //
    flushOnlineList(msgObj: any) {
      console.log(msgObj.onlineList);
      this.onlineUsers = msgObj.onlineList;
    },
    formatMessage(msgObj: any) {
      let reg1 = /\[&bq#(\d{1,3})\]/gim;
      let msg = "";

      let start = 0;
      let res;
      while (true) {
        res = reg1.exec(msgObj.msg);
        if (res == null) {
          break;
        }
        msg += msgObj.msg.substring(start, res.index);
        let IMG = require(`@/assets/bq/${res[1]}.gif`);
        msg += `<img src='${IMG}' />`;
        start = res[0].length + res.index;
      }

      if (start < msgObj.msg.length) {
        msg += msgObj.msg.substring(start);
      }

      msgObj.msg = msg;
    },
    closeBox() {
      this.bqBox.open = false;
    },
    initBqItems(): void {
      const items: Array<any> = [];
      for (let i = 1; i <= 132; i++) {
        items.push({
          name: i,
          img: require("@/assets/bq/" + i + ".gif"),
        });
      }

      (this.bqBox.items as any[]) = items;
    },
    openBox(flag: string): void {
      if (flag == "bq") {
        this.bqBox.open = !this.bqBox.open;
      }
    },
  },
});
</script>

<style lang='less' scoped>
@import url("../assets/iconfont/iconfont.css");
.msg-box {
  min-width: 800px;
  min-height: calc(100vh - 10%);
  max-width: 1000px;
  max-height: calc(100vh - 10%);
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
  position: relative;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  border-radius: 4px;
  overflow: hidden;

  display: flex;
  flex-direction: column;
  justify-content: flex-start;

  &::before {
    z-index: -100;
    content: "";
    position: absolute;
    background-color: rgba(255, 255, 255, 0.5);
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin: -15px;
    filter: blur(15px);
  }

  .msg-box-top {
    width: 100%;
    height: 60px;
    background-color: rgba(0, 0, 0, 0.7);
    text-align: center;
    .title {
      display: inline-block;
      height: inherit;
      line-height: 60px;
      color: ivory;
      -ms-user-select: none;
      user-select: none;
      -webkit-user-select: none;
      -moz-user-select: none;
      font-size: 21px;
      font-family: "Lucida Sans", "Lucida Sans Regular", "Lucida Grande",
        "Lucida Sans Unicode", Geneva, Verdana, sans-serif;
    }
  }

  .msg-box-content {
    flex: 1;
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    .msg-box-content-left {
      flex: 1;
      position: relative;
      .msg-box-content-msg-box {
        position: absolute;
        overflow-x: none;
        overflow-y: auto;
        padding: 15px;
        width: 100%;
        top: 0;
        bottom: 180px;

        .bq-container {
          position: fixed;
          width: 477px;
          min-height: 36px;
          max-height: 210px;
          background-color: rgba(255, 255, 255, 0.9);
          left: 0;
          bottom: 180px;
          border-top: 1px solid rgba(0, 0, 0, 0.2);
          border-right: 1px solid rgba(0, 0, 0, 0.2);
          overflow-y: auto;
          display: flex;
          flex-direction: row;
          justify-content: flex-start;
          flex-wrap: wrap;
          .bq-item {
            display: inline-block;
            width: 35px;
            height: 35px;
            text-align: center;
            border: 1px solid rgba(0, 0, 0, 0.1);
            padding-top: 5px;
            &:hover {
              border-color: rgba(0, 0, 0, 0.7);
            }
          }
        }

        .msg-item {
          display: block;
          width: 100%;
          // background-color: rosybrown;
          min-height: 25px;
          & + .msg-item {
            margin-top: 10px;
          }
          .me-msg {
            text-align: right;
            .name {
              font-weight: 500;
              font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
              display: inline-block;
              padding: 2px 5px;
              width: 60px;
              height: 25px;
              border-radius: 25px;
              background-color: rgba(0, 0, 0, 0.856);
              text-align: center;
              color: #fdfdfd;
            }
            .times {
              font-size: 14px;
              margin-left: 10px;
            }

            .me-msg-box {
              word-break: break-all;
              text-align: left;
              display: inline-block;
              min-width: 120px;
              min-height: 35px;
              max-width: 460px;
              background-color: rgba(22, 22, 22, 0.6);
              border-radius: 5px;
              padding: 10px;
              margin-top: 6px;
              box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.281);
              color: #f3f3f3;
            }
          }
          .you-msg {
            .name {
              font-weight: 500;
              font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
              display: inline-block;
              padding: 2px 5px;
              width: 60px;
              height: 25px;
              border-radius: 25px;
              background-color: rgba(148, 146, 146, 0.2);
              text-align: center;
              color: #3f3e3e;
            }
            .times {
              font-size: 14px;
              margin-left: 10px;
            }

            .you-msg-box {
              display: inline-block;
              min-width: 120px;
              min-height: 35px;
              background-color: rgba(255, 255, 255, 0.6);
              border-radius: 5px;
              padding: 10px;
              margin-top: 6px;
              box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.1);
            }
          }
          .sys-msg {
            text-align: center;
            .times {
              font-size: 13px;
              padding: 5px;
            }
            span.sys-msg-box {
              display: inline-block;
              min-width: 200px;
              padding: 2px 8px;
              background-color: rgba(0, 0, 0, 0.35);
              border-radius: 4px;
              color: rgb(228, 228, 228);
            }
          }
        }
      }
      .msg-box-content-input-box {
        height: 180px;
        width: 100%;
        position: absolute;
        bottom: 0;
        border-top: 1px solid rgba(0, 0, 0, 0.1);
        display: flex;
        flex-direction: column;
        .bq-box {
          height: 40px;
          padding: 2px 15px;
          display: block;

          .icon {
            display: inline-block;
            font-size: 30px;
            font-weight: 500;
            color: rgba(0, 0, 0, 0.5);
            cursor: pointer;
            &:hover {
              transform: skewX(15px);
              color: rgb(0, 0, 0);
              transition: all 0.3s;
            }
            & + .icon {
              margin-left: 15px;
            }
          }
          .icon:nth-child(2) {
            font-size: 27px;
          }

          .icon:nth-child(3) {
            font-size: 20px;
            font-weight: 700;
            position: relative;
            top: -2px;
          }

          .icon:nth-child(4) {
            font-size: 22px;
            font-weight: 700;
            position: relative;
            top: -2px;
          }
        }
        .send-msg-box {
          //   background-color: salmon;
          flex: 1;
          resize: none;
          outline: none;
          border: none;
          background-color: transparent;
          padding: 4px 15px;
          font-size: 16px;
          font-weight: 500;
          font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
        }
        .send-btn-box {
          height: 40px;
          padding: 5px 15px;

          button {
            width: 90px;
            height: 26px;
            float: right;
          }
        }
      }
    }
    .msg-box-content-right {
      width: 230px;
      border-left: 1px solid rgba(0, 0, 0, 0.1);

      display: flex;
      flex-direction: column;

      .top {
        height: 260px;
        text-align: center;
        padding: 40px 10px;

        p + p {
          margin-top: 35px;
        }
        p:nth-child(1) {
          font-size: 22px;
        }
        p:nth-child(2) {
          font-size: 20px;
        }
        p:nth-child(3) {
          text-align: center;
          button {
            width: 90px;
          }
        }
      }
      .bottom {
        flex: 1;
        border-top: 1px solid rgba(0, 0, 0, 0.1);
        padding: 5px;
        .title {
          font-size: 16px;
          color: rgba(0, 0, 0, 0.5);
          text-align: center;
        }
      }
    }
  }
}

.onlin-list {
  ul {
    list-style-type: none;
    width: 100%;
    li {
      padding: 8px;

      font-size: 13px;
      font-weight: 500;
      width: 100%;
      color: rgba(0, 0, 0, 0.7);
      transition: all.5s ease-out;
      &:hover {
        background-color: rgba(107, 191, 240, 0.281);
        padding-left: 15px;
        transition: all 0.8s ease-out;
        color: rgba(0, 0, 0, 0.9);
      }
    }
  }
}
</style>